home *** CD-ROM | disk | FTP | other *** search
- /* 02.04.1989 amn (latest edit) */
-
- /* XPrint.c - low-level printer driver for Macintosh and HP DeskJet. */
-
- /* Compiles into 'DRVR' resource, id 2, name '.XPrint'. */
- /* LightspeedC compiler produces also a 'DATA' resource, id -16320 */
- /* which contains driver's global variables. A handle to these is placed */
- /* into driver's device control entry in 'dCtlStorage' (IM II-190). */
-
- /* These resources are placed into the printer resource file */
- /* 'HP DeskJet', type 'PRER', creator 's89^' as */
- /* 'DRVR' -8192 '.XPrint' and */
- /* 'PREC' -8192. */
-
- /* The 'Chooser' desk accessory changes the name of the active printer resource file */
- /* in the 'STR ' -8192 in 'System' file. */
-
- /* We suppose drivers shouldn't do 'SetResLoad(FALSE)'. */
- /* The application currently running may have decided to do so. */
- /* This is why we try to call 'LoadResource()' even directly after 'GetResource()'. */
- /* LightspeedC driver header code seems to call 'SetResLoad(TRUE)' when processing */
- /* an open call. We hope this doesn't interfere seriously with applications. */
-
- /* Authors: Ari Mujunen (amn@hutcs.hut.fi) and Olli Arnberg (oar@hutcs.hut.fi). */
- /* Copyright Ari Mujunen, Olli Arnberg 1989. */
- /* You may redistribute the driver (=printer resource file, source files, */
- /* documentation file(s), and the file 'Copyright and Source Offer') */
- /* only _non-commercially_ and _in its entirety_. */
- /* See the file 'Copyright and Source Offer' and/or documentation for details. */
- /* Acknowledgements: Special thanks to Mr. Earle R. Horton for his 'Daisy' */
- /* daisywheel printer driver and its source code published in 'MacTutor', Nov-Dec 1987. */
- /* This driver served as a basis and inspiration for our work. It also */
- /* proofed that a Macintosh printer driver can be done despite the lack of */
- /* documentation from Apple. */
-
- /* Change history: */
- /* Version When Who Why */
- /* 2.0 12.11.1988 amn Original rewrite. */
- /* 13.11.1988 amn Getting our globals when we recognize they are not ours. */
- /* 14.11.1988 amn Verifying why 'FKEY' 4 opens us _two_ 1st times. */
- /* 15.11.1988 amn --"-- */
- /* 16.11.1988 amn Found out that we killed Device Manager's dCtlFlags */
- /* low-order byte by storing directly to it. */
- /* Cleaning off 'asm's. */
- /* 18.11.1988 amn Preparing to use fewer globals. */
- /* 19.11.1988 amn Globals reduced, comments checked. */
- /* 20.11.1988 amn Getting the volume of 'System' file. */
- /* 21.11.1988 amn Names in 'prglobal.h' changed. */
- /* 24.11.1988 amn Read printed listing... */
- /* 25.11.1988 amn Checking the magic number in our globals correctly. */
- /* 26.11.1988 amn Set 'dCtlFlags' every time we are opened. */
- /* The actual error was an extraneous semicolon */
- /* in the 'if' statement opening serial driver. */
- /* 27.11.1988 amn Searching for a memory overwrite problem. */
- /* Found it: used a global before they were read from resource. */
- /* 12.12.1988 amn Grouping of consecutive empty bit lines to one DJ command. */
- /* 03.02.1989 amn Moving RESID-constants to prglobals.h. */
- /* 06.02.1989 amn/oar Dropping compression when in LaserJet compatibility mode. */
- /* 25.02.1989 amn Searching why this still compresses while in LJC-mode. */
- /* Don't know, now it definitely does not compress in LJC-mode. */
- /* 24.03.1989 amn Adding detection of dirty and non-dirty bit lines in LJC-mode. */
- /* 25.03.1989 amn/oar Removing global resource file refNums. */
- /* Does not deallocate globals when closed: MF-compatibility. */
- /* 26.03.1989 amn Reload 'Stng' and 'STR#' every time opened */
- /* so Chooser changes take effect immediately. */
- /* 28.03.1989 amn Settable printer origin. */
- /* 2.1 02.04.1989 amn,oar Released version. */
-
-
- #include "common_mac_includes.h"
-
- /* Mac OS includes specific to this module: */
- #include <ResourceMgr.h>
- /* #include <Environs.h> we don't have this feature. */
- #include <SerialDvr.h>
- /* #include <HFS.h>: (needs FileMgr.h); we don't have this feature. */
-
-
- #define DRIVER_MODULE
- #include "prglobals.h"
-
-
- /* Device driver routine numbers. LightspeedC passes this number as a routine */
- /* selector value in the third integer parameter to the function 'main'. */
- #define OPEN 0
- #define PRIME 1
- #define CONTROL 2
- #define STATUS 3
- #define CLOSE 4
-
- /* Control command codes (csCode) for the serial driver. */
- #define SERIAL_RESET 8
- #define SERIAL_HANDSHAKE 10
-
- /* Xon/Xoff characters to be used when handshaking is requested from the serial driver. */
- #define XON_CHAR ((char)17)
- #define XOFF_CHAR ((char)19)
-
-
- /* Font characterization table for use by FontManager and XPrint. */
- typedef struct {
- int vres;
- int hres;
- SignedByte bold[3];
- SignedByte italic[3];
- SignedByte notused[3];
- SignedByte outline[3];
- SignedByte shadow[3];
- SignedByte condensed[3];
- SignedByte extended[3];
- SignedByte underline[3];
- } tFontCharacterizationTable, *ptFontCharacterizationTable, **htFontCharacterizationTable;
-
-
- /* Function prototypes for every function in this source file.*/
-
- /* Device driver entry point. LightspeedC generates code to call this function. */
- int main(ptPrParam, DCtlPtr, int);
-
- /* Routine which opens our device driver. Get our global variables */
- /* as a resource 'PREC', id -8192, load them into memory and lock them down. */
- /* Load settings resource 'Stng', id -4080 into global struct 'currentSettings'. */
- OSErr driverOpen(DCtlPtr);
-
- /* Open ourselves (=printer resource file) and */
- /* return the refNum of our printer resource file. */
- int openPrinterResourceFile(DCtlPtr);
-
- /* Load 'Sntg' and 'STR#' settings into globals. */
- OSErr reloadSettings(void);
-
- /* Low-level driver must be capable of sending printer controls as FF, LF etc. in */
- /* a device-independent manner. These routines fetch the actual control strings from */
- /* settings resource 'STR#', id -4080. */
- void setControlStrings(StringHandle);
- void copyPascalString(StringPtr, StringPtr);
- void decodeCaretsToControlCharacters(StringPtr);
-
- /* Actual printing is done using Mac serial driver called '.AOut'/'.BOut'. */
- /* The driver is never closed, because the old 64K ROM serial driver hangs the */
- /* machine when closed. Hardware (CTS) handshaking is strongly recommended. */
- OSErr openSerialDriverAndConfigureIt(void);
- OSErr openDriverByName(StringPtr);
- void reconfigureSerialPort(void);
-
- /* Routines that send characters to the serial line and the printer. */
- OSErr sendPrinterControl(long);
- OSErr sendString(StringPtr);
-
- /* Routines that compress and send a bitmap to the printer. */
- OSErr printBitMap(int, BitMap, Rect);
- void compressBitLine(int, StringPtr, int *, StringPtr, Boolean *);
-
-
- /* Function definitions. */
-
- int
- main(
- pb, /* ==> parameter block with which we were called*/
- dce, /* ==> device control entry */
- routineSelector /* which of OPEN, PRIME, CONTROL, STATUS, CLOSE */
- )
- ptPrParam pb;
- DCtlPtr dce;
- int routineSelector;
- {
- /* Check to make sure our data area was allocated. We cannot image how this code */
- /* can be in memory unless the OPEN routine is called first. */
- /* Note that we cannot use any of LightspeedC's "global" variables */
- /* until after we get our storage from the resource file and lock it down, */
- /* making A4 point to it. This probably does the same thing that the prolog code */
- /* attempts to do with the original 'DATA' resource created by LightspeedC. */
-
- OSErr retCode;
-
- if (!((routineSelector == OPEN) || (routineSelector == CLOSE))) {
- if (dce->dCtlStorage == nil)
- SysError(25); /* somebody managed to call CONTROL/STATUS before OPEN */
- if ((*(long *)(*dce->dCtlStorage)) != OUR_MAGIC_NUMBER)
- SysError(25); /* it is not ours */
-
- /* Now we have our globals (dce->dCtlStorage), ensure lockedness: */
- HLock(dce->dCtlStorage);
-
- /* Make LSC use the locked storage as its globals: */
- {
- Ptr pointer;
-
- /* Strip off Memory Manager bits. */
- pointer = (Ptr)((long)(*(dce->dCtlStorage)) & (Lo3Bytes));
- asm {
- movea.l pointer,a4 ;; LSC uses A4 as the base for driver globals
- }
- }
- } /* end if other than CLOSE */
-
- switch (routineSelector) { /* dispatch */
-
- case OPEN:
- /* Applications seem to call this often to ensure our driver is open. */
- /* 'FKEY' 4, screen print, opens us after it has noticed that the first */
- /* screen dump call failed because the driver isn't open (and not in memory). */
- /* The Device Manager of System 2.0 calls us despite we are open. */
- /* System 4.2 does not seem to call any longer. */
-
- if (dce->dCtlStorage != nil)
- if ((*(long *)(*dce->dCtlStorage)) != OUR_MAGIC_NUMBER) {
- DisposHandle(dce->dCtlStorage); /* is is not ours, dispose it */
- dce->dCtlStorage = nil;
- }
- if (dce->dCtlStorage == nil) {
- if ((retCode = driverOpen(dce)) != noErr) {
- PrintErr = retCode;
- (void)CloseDriver(dce->dCtlRefNum); /* calls recursively ??? */
- return(retCode);
- }
- }
-
- /* If we are reopened by Chooser, the (possibly) changed settings */
- /* must be reloaded. */
- if ((retCode = reloadSettings()) != noErr)
- return(retCode);
- reconfigureSerialPort();
-
- dce->dCtlFlags = dCtlEnable | dStatEnable | (dce->dCtlFlags & 0x00FF);
- /* Locking is not requested, BUT just in case high-level printing code */
- /* manages to get memory by purging our driver doesn't seem fair... */
- /* Perhaps the resource bit 'Purgeable' should be cleared ??? */
-
- /* Printer driver version. */
- dce->dCtlQHdr.qFlags = PRINTING_MANAGER_VERSION; /* Yes, it seems to be there !!! */
-
- PrintErr = noErr; /* Somebody may bother to check this. */
- break; /* case OPEN */
-
- case PRIME:
- /* Read/write calls not for low-level printer drivers. */
- break;
-
- case CONTROL:
- switch (pb->csCode) {
- /* 'pb->csCode' gives opcode, and we switch on */
- /* it to perform low-level Printing calls. */
-
- case iPrBitsCtl: /* Send bitmap to printer. */
- {
- BitMap *pBitMapPtr;
- Rect *pPortRectPtr;
- int resolution;
-
- pBitMapPtr = (BitMap *)(pb->lParam1);
-
- pPortRectPtr = (Rect *)(pb->lParam2);
-
- if (pb->lParam3 == lScreenBits)
- resolution = 100;
- else
- if (pb->lParam3 == lPaintBits)
- resolution = 75;
- else
- resolution = (int)(pb->lParam3);
-
- return( printBitMap(
- resolution,
- *pBitMapPtr,
- *pPortRectPtr)
- );
- }
- break;
-
- case iPrIOCtl: /* Text streaming. */
- serialParameterBlock.ioParam.ioBuffer = (Ptr)pb->lParam1;
- serialParameterBlock.ioParam.ioReqCount = pb->lParam2;
- return(PBWrite(&serialParameterBlock, FALSE));
- break;
-
- case iPrEvtCtl: /* Screen print. */
- {
- BitMap *screenBitsPtr;
-
- /* Fetch the QuickDraw global var. screenBits */
- screenBitsPtr = (BitMap *)(*((Ptr *)(CurrentA5))
- - (Ptr)(5*sizeof(Pattern) + sizeof(Cursor) + sizeof(BitMap)));
- return( printBitMap(
- currentSettings.screenDumpResolution,
- *screenBitsPtr,
- screenBitsPtr->bounds)
- );
-
- /* We should heed the 'pb->lParam1' being == 'lPrEvtTop' */
- /* which means only the top window should be printed. */
- /* Then we should remember to HideCursor() before print. */
- /* Currently our bit map print cannot use .left and .right */
- /* of portRect passed to it, only .top and .bottom. */
- }
- break;
-
- case iPrDevCtl: /* CR, LF, FF, etc */
- return(sendPrinterControl(pb->lParam1));
- break;
-
- case iFMgrCtl:
- /* Font table modify request. pb->lParam1 is a
- pointer to an FMInput record. (IM says we get an
- FMOutputPtr here but MacsBug says we get a pointer to
- FMInput. I go with MacsBug.) In addition, the
- integer following pb->lParam1 contains our driver
- reference number and a private byte we can use
- internally. The application first does something
- to determine the characteristics of fonts in our
- printing GrafPort. The FontManager calls our
- status routine with csParam = 8 and we give it a
- "font characterization table". The FontManager
- selects a font, and calls our control routine to
- confirm the choice. */
- {
- /* Currently we do no modifications. */
- }
- break;
-
- goodBye:
- /* Application heap is about to be reinitialized. */
- /* Currently the is nothing special to be done: */
- /* All allocated memory is in the application heap */
- /* and the ROM serial driver must not be closed. */
- /* If you add some code here, remember to change dCtlFlags */
- /* in 'driverOpen()'. */
- break;
-
- killCode:
- /* Killing all pending (serial) I/O is requested. */
- /* Should we be able to do it ??? Isn't all serial I/O */
- /* done synchronously ??? Don't WE do it synchronously ??? */
- break;
-
- default:
- break;
- }
- break; /* case CONTROL */
-
- case STATUS:
- switch (pb->csCode) {
- /* pb->csCode gives opcode, and we switch on it to */
- /* perform low-level Printing calls. */
- case iFMgrCtl:
- /* Font Manager font characterization table request. */
- /* 'pb->lParam1' is a pointer to an area in memory */
- /* in which to put a copy of the information */
- /* describing our font capabilities/directions to QuickDraw. */
- /* 'pb->lParam2' has an integer in its high order word */
- /* which contains the device information from printing */
- /* port's 'grafDevice' field. This is set from print record */
- /* (print.prInfoPT.iDev and print.prStl.wDev) */
- /* by high-level printing code -- there it was */
- /* set by style dialog (PDEF 4). */
- /* High order byte contains our driver's reference number so */
- /* font manager could call our driver. Low order byte contains */
- /* our resolution information which we use to select the correct */
- /* table from our resources. */
- {
- htFontCharacterizationTable myFonts;
- int resolution;
-
- resolution = (int)(pb->lParam2 >> 16) & RES_MASK;
- myFonts = (htFontCharacterizationTable)GetResource(
- 'FCHT',
- RESID_OWNED_BY_PDEF+resolution
- );
- if (myFonts == nil)
- return(ResError());
- LoadResource(myFonts);
- *((ptFontCharacterizationTable)pb->lParam1) = **myFonts;
- }
- break;
- default:
- break;
- }
- break; /* case STATUS */
-
- case CLOSE:
- /* Applications seldom close our driver: to do this, they should call */
- /* 'PrDrvrClose' in addition to PrClose (see IM II-157). */
- /* Closing the driver seems to be reserved for 'Chooser' */
- /* when it changes the active printer resource file. */
-
- /* Don't reference any driver global variables here: */
- /* We don't know if they are allocated or not. */
-
- /* In MultiFinder we cannot know if another application */
- /* needs us despite another wants to close. */
- /* So we don't deallocate our globals: this has the unfortunate */
- /* side effect: using Chooser leaves a block of them floating. */
- /***
- if (dce->dCtlStorage != nil) {
- (*(long *)(*dce->dCtlStorage)) = 0L; / * destroy our magic number * /
- DisposHandle(dce->dCtlStorage);
- dce->dCtlStorage=nil;
- }
- ***/
- break;
-
- default:
- /* Device drivers have only OPEN, PRIME, CONTROL, STATUS, and CLOSE. */
- break;
- } /* switch routineSelector */
-
- /* Changing the low-memory global 'PrintErr' is reserved for high-level printing */
- /* code -- don't change it here except for OPEN call. */
- /* 'PrintErr' must retain its value (as set for example when writing to spool file) */
- /* despite calls to low-level driver. */
-
- return(noErr);
- } /* main */
-
-
- OSErr
- driverOpen(dce)
- DCtlPtr dce;
- {
- OSErr retCode;
-
- if (openPrinterResourceFile(dce) == -1)
- return(dInstErr); /* 'couldn't find driver in resource file' ??? */
-
- /* Get driver's initialized control storage from printer resource file, */
- /* lock it, and make A4 point to it thus LSC can use variables in it like globals. */
-
- if ((dce->dCtlStorage = (Handle)GetResource('PREC', RESID_OWNED_BY_PDEF)) == nil)
- return(ResError());
-
- {
- Handle storage;
- Ptr pointer;
-
- storage = dce->dCtlStorage;
- LoadResource(storage);
- DetachResource(storage);
- HNoPurge(storage);
- HLock(storage);
-
- /* Strip off Memory Manager bits from the pointer. */
- pointer = (Ptr)((long)(*storage) & (Lo3Bytes));
- asm {
- movea.l pointer,a4 ;; LSC uses A4 as the base for driver globals
- }
- }
-
- /* Now our globals are accessible. */
-
- /* theWorld = myWorld; ??? */
-
- if ((retCode = reloadSettings()) != noErr)
- return(retCode);
-
- if ((retCode = openSerialDriverAndConfigureIt()) != noErr)
- return(retCode);
-
- /* High-level driver (PDEF0&5) communicates with low-level (XPrint) */
- /* using this initialized global parameter block 'xPrintParameterBlock'. */
- /* Now we initialize the pointer to the name of the driver: */
- xPrintParameterBlock.ioNamePtr = xPrintName;
- /*== #define sPrDrvr from <PrintMgr.h>, */
- /* initialized in "prglobals.h". */
-
- return(noErr);
- } /* driverOpen */
-
-
- int
- openPrinterResourceFile(dce)
- DCtlPtr dce;
- /* Find the system folder and ensure our printer resource file is open. */
- /* Fill in a global SysEnvRec, which might be useful for other stuff. */
- {
- /*** SysEnvRec myWorld; ***/
- StringHandle ourname;
- int theRefNum;
- OSErr retCode;
-
- /* Should not be called if we have something allocated. */
- if (dce->dCtlStorage != nil)
- SysError(25);
-
- /* Find the name of our printer resource file. It is in the System file. */
- if ((ourname = (StringHandle)GetResource('STR ', RESID_OWNED_BY_PDEF)) == nil)
- return(-1);
-
- LoadResource(ourname);
- HLock(ourname);
- /*** SysEnvirons(1, &myWorld); ***/
- /*** if (myWorld.machineType >= envMachUnknown)
- theRefNum = OpenRFPerm(*ourname, myWorld.sysVRefNum, fsCurPerm);
- else ***/ {
- int systemResFile;
-
- /* Get the actual reference number of system file. */
- {
- int saveResFile;
-
- saveResFile = CurResFile();
- UseResFile(0); /* System file, IM I-117. */
- systemResFile = CurResFile();
- UseResFile(saveResFile);
- }
-
- {
- int saveVolRefNum;
- Str255 saveVolName;
- int systemVolumeRefNum;
-
- /* Save current volume refNum. */
- if (GetVol(&saveVolName, &saveVolRefNum) != noErr) /* save current default volume */
- saveVolRefNum = 0; /* We hope 0 is not a legal volume reference number. */
-
- /* Get the volume where system file resides. */
- theRefNum = -1;
- if (GetVRefNum(systemResFile, &systemVolumeRefNum) == noErr)
- if (SetVol(nil, systemVolumeRefNum) == noErr) /* open in the same folder as System */
- theRefNum = OpenResFile(*ourname);
- /* theRefNum == opened resource file refNum or -1 */
-
- if (saveVolRefNum != 0)
- SetVol(nil, saveVolRefNum); /* restore current default volume */
- }
- }
- HUnlock(ourname);
- HPurge(ourname);
- return(theRefNum);
- } /* openPrinterResourceFile */
-
-
- OSErr
- reloadSettings()
- {
- htSettings hSettings;
- StringHandle hStrings;
-
- if ((hSettings = (htSettings)GetResource('Stng',RESID_OWNED_BY_PDEF)) == nil)
- return(ResError());
- LoadResource(hSettings);
- HNoPurge(hSettings);
- currentSettings = **hSettings;
- HPurge(hSettings);
-
- if ((hStrings = (StringHandle)GetResource('STR#',RESID_OWNED_BY_CHOOSER_PACK)) == nil)
- return(ResError());
- LoadResource(hStrings);
- HLock(hStrings);
- setControlStrings(hStrings);
- HUnlock(hStrings);
- HPurge(hStrings);
- } /* reloadSettings */
-
-
- void
- setControlStrings(myStrings)
- StringHandle myStrings;
- {
- StringPtr strptr;
-
- copyPascalString( (strptr = (*myStrings)+2) , prlfstr);
- copyPascalString( (strptr += (*strptr) + 1) , prinitstr);
- copyPascalString( (strptr += (*strptr) + 1) , prtopstr);
- copyPascalString( (strptr += (*strptr) + 1) , preopstr);
- copyPascalString( (strptr += (*strptr) + 1) , preofstr);
- decodeCaretsToControlCharacters(prlfstr);
- decodeCaretsToControlCharacters(prinitstr);
- decodeCaretsToControlCharacters(prtopstr);
- decodeCaretsToControlCharacters(preopstr);
- decodeCaretsToControlCharacters(preofstr);
- } /* setControlStrings */
-
-
- void
- copyPascalString(src, dst)
- StringPtr src, dst;
- /* This is for copying PASCAL strings (simple) */
- {
- asm {
- clr.l d0
- move.l src,a0
- move.l dst,a1
- move.b (a0),d0
- loop:
- move.b (a0)+,(a1)+
- dbra d0,@loop
- }
- } /* copyPascalString */
-
-
- void
- decodeCaretsToControlCharacters(str)
- StringPtr str;
- {
- register unsigned char i, count;
-
- count = 1;
- for (i=0; str[0]-i++;) {
- if (str[i] == '^')
- str[count] = 31 & str[++i];
- else
- str[count] = str[i];
- count++;
- }
- str[0] = count - 1;
- } /* decodeCaretsToControlCharacters */
-
-
- OSErr
- openSerialDriverAndConfigureIt()
- /* Open serial driver and configure it. Use low-level ROM routines. */
- {
- OSErr retCode;
-
- switch (currentSettings.port) {
- case 0: /* modem port */
- retCode = openDriverByName((StringPtr)"\p.AOut");
- break;
- case 1: /* printer port */
- retCode = openDriverByName((StringPtr)"\p.BOut");
- break;
- }
- if (retCode != noErr)
- return(retCode);
-
- /* Set up the I/O parameter block for writing to the serial driver. */
- reconfigureSerialPort();
-
- return(noErr);
- } /* openSerialDriverAndConfigureIt */
-
-
- OSErr
- openDriverByName(name)
- Str255 name;
- /* Open a driver by name. ROM, Ram, serial driver? Who cares? */
- {
- serialParameterBlock.ioParam.ioNamePtr = name;
- serialParameterBlock.ioParam.ioCompletion = nil;
- serialParameterBlock.ioParam.ioPermssn = fsCurPerm;
- return(PBOpen(&serialParameterBlock, FALSE));
- } /* openDriverByName */
-
-
- /* Set up the I/O parameter block for writing to the serial driver. */
- /* A control call resets the baud rate, another the handshaking method. */
- void
- reconfigureSerialPort()
- {
- ParmBlkPtr pb;
- int serialDriverRefNum;
- int serialConfigWord;
-
- switch (currentSettings.port) {
- case 0: /* modem port */
- serialDriverRefNum = AoutRefNum;
- break;
- case 1: /* printer port */
- serialDriverRefNum = BoutRefNum;
- break;
- }
-
- pb = &serialParameterBlock;
- pb->ioParam.ioRefNum = serialDriverRefNum;
- pb->ioParam.ioCompletion = nil;
-
- ((cntrlParam *)pb)->csCode = SERIAL_RESET;
- serialConfigWord = data8 + noParity + stop20;
- serialConfigWord += currentSettings.baud;
- ((cntrlParam *)pb)->csParam[0] = serialConfigWord;
- (void)PBControl(pb, FALSE); /* Always returns 'noErr' according to IM II-251 */
-
- #define shake ((SerShk*)&((cntrlParam*)pb)->csParam[0])
- shake->errs = FALSE;
- shake->evts = FALSE;
- shake->fDTR = FALSE;
- shake->fInX = FALSE;
- /* if (currentSettings.XonXoff && (theWorld.machineType) >= envMachUnknown)) { ???
- shake->fXOn = TRUE;
- shake->fCTS = FALSE;
- shake->xOn = XON_CHAR;
- shake->xOff = XOFF_CHAR;
- }
- else { */
- shake->fXOn = FALSE;
- shake->fCTS = TRUE;
- /* } */
- ((cntrlParam *)pb)->csCode = SERIAL_HANDSHAKE;
- (void)PBControl(pb, FALSE); /* Always returns 'noErr' according to IM II-251 */
- #undef shake
-
- pb->ioParam.ioPosMode = 0;
- pb->ioParam.ioPosOffset = 0;
- } /* reconfigureSerialPort */
-
-
- OSErr
- sendPrinterControl(code)
- long code;
- /* printer device control calls */
- {
- switch(code) {
- case lPrReset:
- return(sendString(prinitstr));
- case lPrPageEnd:
- return(sendString(preopstr));
- case lPrLineFeed:
- case lPrLFSixth:
- case lPrLFEighth:
- return(sendString(prlfstr));
- default:
- return(controlErr);
- }
- } /* sendPrinterControl */
-
-
- OSErr
- sendString(string)
- StringPtr string;
- /* printer control string to serial driver */
- {
- serialParameterBlock.ioParam.ioBuffer = (Ptr)(string+1);
- serialParameterBlock.ioParam.ioReqCount = (long)(string[0]);
- return(PBWrite(&serialParameterBlock, FALSE));
- } /* sendString */
-
-
- OSErr
- printBitMap(resolution, dumpBitMap, dumpPortRect)
- int resolution;
- BitMap dumpBitMap;
- Rect dumpPortRect;
- {
- Str255 numAsString;
- int i;
- OSErr retCode;
-
- int compressedLineLength;
- unsigned char compressedBitLine[500]; /* ??? LineLength+(LineLength/128) */
-
-
- /* Set bit map resolution */
- switch (resolution) {
- case 75:
- retCode = sendString((StringPtr)"\p\033*t75R");
- break;
- case 100:
- retCode = sendString((StringPtr)"\p\033*t100R");
- break;
- case 150:
- retCode = sendString((StringPtr)"\p\033*t150R");
- break;
- case 300:
- retCode = sendString((StringPtr)"\p\033*t300R");
- break;
- default:
- retCode = controlErr;
- break;
- }
- if (retCode != noErr)
- return(retCode);
-
- /* Start graphics */
- if ((retCode = sendString((StringPtr)"\p\033*r0A")) != noErr)
- return(retCode);
-
- /*
- Here we must convert the bit image from Mac into 'Compaction Graphics Mode 2'.
-
- The mode is as follows:
-
- a repeat count (-1 to -127) followed by data byte to repeated
- or
- block length (0 to 127) followed by block length + 1 data bytes
-
- */
-
- /* Currently we use either uncompacted graphics mode 0 or */
- /* compacted graphics mode 2. */
- if (currentSettings.useOnlyPCLLevel3Features) {
- retCode = sendString((StringPtr)"\p\033*b0M");
- }
- else {
- retCode = sendString((StringPtr)"\p\033*b2M");
- }
- if (retCode != noErr)
- return(retCode);
-
- for (i=(dumpPortRect.top - dumpBitMap.bounds.top);
- i<(dumpPortRect.bottom - dumpBitMap.bounds.top);
- i++) {
-
- Boolean bitLineContainsAtLeastOneBlackPixel;
-
- /* compress */
- compressBitLine(
- dumpBitMap.rowBytes,
- (StringPtr)(dumpBitMap.baseAddr + (i*(dumpBitMap.rowBytes))),
- &compressedLineLength,
- compressedBitLine,
- &bitLineContainsAtLeastOneBlackPixel
- );
-
-
- if (bitLineContainsAtLeastOneBlackPixel)
- /* PTT will test if LaserJet cad do positioning by 1/300": */
- /*** || currentSettings.useOnlyPCLLevel3Features) ***/
- {
- /* Start of line */
- if ((retCode = sendString((StringPtr)"\p\033*b")) != noErr)
- return(retCode);
- NumToString((long)compressedLineLength, numAsString);
- if ((retCode = sendString(numAsString)) != noErr) /* line length */
- return(retCode);
- if ((retCode = sendString((StringPtr)"\pW")) != noErr)
- return(retCode);
-
- /* Send the string to printer. */
- serialParameterBlock.ioParam.ioBuffer = (Ptr)compressedBitLine;
- serialParameterBlock.ioParam.ioReqCount = (long)compressedLineLength;
- if ((retCode = PBWrite(&serialParameterBlock, FALSE)) != noErr)
- return(retCode);
- }
- else {
- int numberOfConsecutiveEmptyBitLines;
-
- i++;
- numberOfConsecutiveEmptyBitLines = 1;
- while(TRUE) {
- compressBitLine(
- dumpBitMap.rowBytes,
- (StringPtr)(dumpBitMap.baseAddr + (i*(dumpBitMap.rowBytes))),
- &compressedLineLength,
- compressedBitLine,
- &bitLineContainsAtLeastOneBlackPixel
- );
- if (bitLineContainsAtLeastOneBlackPixel)
- break;
- i++;
- numberOfConsecutiveEmptyBitLines++;
- }
-
- /* Skip empty lines using HP DeskJet specific command. */
- if ((retCode = sendString((StringPtr)"\p\033*p+")) != noErr)
- return(retCode);
- NumToString((long)((300/resolution) * numberOfConsecutiveEmptyBitLines), numAsString);
- if ((retCode = sendString(numAsString)) != noErr) /* bit lines to skip */
- return(retCode);
- if ((retCode = sendString((StringPtr)"\pY")) != noErr)
- return(retCode);
-
- /* Continue processing (possible) non-empty line again. */
- i--;
- }
-
- } /* for */
-
- /* End graphics */
- return(sendString((StringPtr)"\p\033*rB"));
-
- } /* printBitMap */
-
-
- void
- compressBitLine(lineLength, bitLine, compressedLineLength, compressedBitLine, dirty)
- int lineLength;
- StringPtr bitLine;
- int *compressedLineLength;
- StringPtr compressedBitLine;
- Boolean *dirty;
- {
- int i, k, m, state;
- Str255 String;
-
- if (currentSettings.useOnlyPCLLevel3Features) {
- BlockMove(bitLine, compressedBitLine, (Size)lineLength);
- *compressedLineLength = lineLength; /* length does not change */
- *dirty = FALSE;
- for (i=0;i<lineLength;i++)
- if (bitLine[i] != (unsigned char)0)
- *dirty = TRUE;
- return;
- }
-
- #define INITIAL 0
- #define SAME 1
- #define DIFFERENT 2
-
- #ifdef DEBUG_COMPRESSING_STATE_MACHINE
- sendString((StringPtr)"\p\n\rcompressString(lineLength=");
- NumToString((long)lineLength, String);
- sendString(String);
- sendString((StringPtr)"\p, bitLine=");
- NumToString((long)(bitLine), String);
- sendString(String);
- sendString((StringPtr)"\p, compressedLineLength=");
- NumToString((long)(compressedLineLength), String);
- sendString(String);
- sendString((StringPtr)"\p, compressedBitLine=");
- NumToString((long)(compressedBitLine), String);
- sendString(String);
- sendString((StringPtr)"\p);\n\r");
- #endif DEBUG_COMPRESSING_STATE_MACHINE
-
- i = 0; /* input buffer */
- k = 0; /* output buffer */
- m = 0; /* number of bytes in a group (max. 128) */
- state = INITIAL;
- *dirty = FALSE;
-
- while (TRUE) {
- if (bitLine[i] != (unsigned char)0)
- *dirty = TRUE;
-
- #ifdef DEBUG_COMPRESSING_STATE_MACHINE
- sendString((StringPtr)"\pstate=");
- NumToString((long)state, String);
- sendString(String);
- sendString((StringPtr)"\p, i=");
- NumToString((long)i, String);
- sendString(String);
- sendString((StringPtr)"\p, bitLine[i]=");
- NumToString((long)(bitLine[i]), String);
- sendString(String);
- sendString((StringPtr)"\p, bitLine[i+1]=");
- NumToString((long)(bitLine[i+1]), String);
- sendString(String);
- sendString((StringPtr)"\p, k=");
- NumToString((long)k, String);
- sendString(String);
- sendString((StringPtr)"\p, m=");
- NumToString((long)m, String);
- sendString(String);
- sendString((StringPtr)"\p\n\r");
- #endif DEBUG_COMPRESSING_STATE_MACHINE
-
- switch (state) {
- case INITIAL: {
- if (i >= lineLength)
- goto outOfWhile; /* input buffer finished */
-
- if (i == (lineLength-1)) {
- compressedBitLine[k++] = 0; /* 1 different byte */
- compressedBitLine[k++] = bitLine[i];
- goto outOfWhile;
- }
-
- if (bitLine[i] == bitLine[i+1]) {
- state = SAME;
- }
- else {
- state = DIFFERENT;
- }
- break;
- } /* case INITIAL */
-
- case SAME: {
- if (i >= lineLength)
- goto outOfWhile; /* input buffer finished */
-
- if (i == (lineLength-1)) { /* ends with at least 2 same bytes */
- compressedBitLine[k++] = (unsigned char)(- m); /* repeat count: 2 -> -1, 3 -> -2 etc. */
- compressedBitLine[k++] = bitLine[i];
- goto outOfWhile; /* input buffer finished */
- }
-
- if (m >= 126) {
- compressedBitLine[k++] = (unsigned char)(- m); /* repeat count: 2 -> -1, 3 -> -2 etc. */
- compressedBitLine[k++] = bitLine[i]; /* last same byte of this group */
- i++; /* the first byte of next group (same/different, don't know yet) */
- m = 0;
- state = INITIAL;
- break;
- }
-
- if (bitLine[i] == bitLine[i+1]) {
- i++;
- m++; /* Yippee, one more! */
- state = SAME;
- break;
- }
- else {
- compressedBitLine[k++] = (unsigned char)(- m); /* repeat count: 2 -> -1, 3 -> -2 etc. */
- compressedBitLine[k++] = bitLine[i]; /* last same byte of this group */
- i++; /* the first byte of next group (same/different, don't know yet) */
- m = 0;
- state = INITIAL;
- break;
- }
- break;
- } /* case SAME */
-
- case DIFFERENT: {
- if (i >= lineLength)
- goto outOfWhile; /* input buffer finished */
-
- if (i == (lineLength-1)) { /* line ends with at least two different bytes */
- i -= m;
- compressedBitLine[k++] = (unsigned char)(m); /* char count: 2 -> 1, 3 -> 2 etc. */
- for (;m>=0;m--)
- compressedBitLine[k++] = bitLine[i++];
- goto outOfWhile; /* input buffer finished */
- }
-
- if (m >= 126) {
- i -= m;
- compressedBitLine[k++] = (unsigned char)(m); /* char count: 2 -> 1, 3 -> 2 etc. */
- for (;m>=0;m--)
- compressedBitLine[k++] = bitLine[i++];
- m = 0;
- state = INITIAL;
- break;
- }
-
- if (bitLine[i] != bitLine[i+1]) {
- i++;
- m++; /* Yippee, one more! */
- state = DIFFERENT;
- break;
- }
- else {
- i -= m;
- compressedBitLine[k++] = (unsigned char)(m); /* char count: 2 -> 1, 3 -> 2 etc. */
- for (;m>=0;m--)
- compressedBitLine[k++] = bitLine[i++];
- m = 0;
- state = INITIAL;
- break;
- }
- break;
- } /* case DIFFERENT */
- } /* switch */
- } /* while */
-
- outOfWhile:
- *compressedLineLength = k;
- } /* compressBitLine */
-